package auth

import (
	"context"
	"coolcar/v1/auth/api/gen/v1"
	"coolcar/v1/auth/dao"
	"coolcar/v1/shared/ids"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"time"
)

// Service implements auth service.
type Service struct {
	Sugar       *zap.SugaredLogger
	Mongo       *dao.Mongo
	TokenExpire time.Duration
	OpenIDResolver
	TokenGenerator
}

// OpenIDResolver resolves an authorization code.
type OpenIDResolver interface {
	Resolve(code string) (string, error)
}

// TokenGenerator generates a token for the specified account ID.
type TokenGenerator interface {
	Generate(aid ids.AccountID, expired time.Duration) (string, error)
}

// Login logs a user in.
func (s *Service) Login(ctx context.Context, request *authpb.LoginRequest) (*authpb.LoginResponse, error) {
	openid, err := s.OpenIDResolver.Resolve(request.Code)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, "failed to resolve openid: %v", err)
	}
	aid, err := s.Mongo.ResolveAccountID(ctx, openid)
	if err != nil {
		s.Sugar.Errorf("failed to Resolve AccountID: %v", err)
		return nil, status.Errorf(codes.Internal, "failed to Resolve accountID: %v", err)
	}

	token, err := s.TokenGenerator.Generate(aid, s.TokenExpire)
	if err != nil {
		s.Sugar.Errorf("failed to generates token: %v", err)
		return nil, status.Errorf(codes.Internal, "failed to generates token: %v", err)
	}
	return &authpb.LoginResponse{
		AccessToken: "bearer " + token,
		ExpiresIn:   int32(s.TokenExpire.Seconds()),
	}, nil
}
